%% ---
%%  Excerpted from "Programming Erlang",
%%  published by The Pragmatic Bookshelf.
%%  Copyrights apply to this code. It may not be used to create training material, 
%%  courses, books, articles, and the like. Contact us if you are in doubt.
%%  We make no guarantees that this code is fit for any purpose. 
%%  Visit http://www.pragmaticprogrammer.com/titles/jaerlang for more book information.
%%---

-module(chat_server).
-import(lib_chan_mm, [send/2, controller/2]).
-import(lists, [delete/2, foreach/2, map/2, member/2,reverse/2]).

-compile(export_all).


start() ->
    start_server(),
    lib_chan:start_server("chat.conf").

start_server() ->
    register(chat_server, 
	     spawn(fun() ->
			   process_flag(trap_exit, true),
			   Val= (catch server_loop([])),
			   io:format("Server terminated with:~p~n",[Val])
		   end)).


server_loop(L) ->
    receive
	{mm, From, {login, Group, Nick}} ->
	    case lookup(Group, L) of
		{ok, Address, Port, _} ->
			send(From, {connect_group, Group, Nick, Address, Port}),
			io:format("user ~p (~p) is about to connect in group ~p~n", [Nick, From, Group]),
		    server_loop(L);
		error ->
			send(From, {create_group, Group, Nick}),
			io:format("waiting ~p (~p) to create the group ~p~n", [Nick, From, Group]),
			% Espera confirmação de que o cliente criou o grupo
			receive
			    {mm, Channel, {ack, Group, Address, Port}} ->
     			    io:format("group ~p (~p) has been created~n", [Group, Channel]),
		            server_loop([{Group, Address, Port, Channel}|L])
		    after 10000 ->
		        server_loop(L)
		    end
	    end;
	% ex 5
	{mm, _From, {groupDied,Group}} ->
	    L1 = remove_group(Group, L),
	    server_loop(L1);
	% ex 5
	{mm_closed, _Pid} ->
	    server_loop(L); 
	%% Ex 2
	{mm, From, {get_nicks_in_group, Group}} ->
	    case lookup(Group, L) of
		{ok, _, _, Channel} ->
			send(Channel, get_nicks),
			Reply = wait_get_nicks_response(),
			send(From, Reply),
			server_loop(L);
		error ->
		    send(From,{nicks_in_group, group_does_not_exist}),
		    server_loop(L)
	    end;
	%% Ex 2
	%% Ex 3
	{mm, From, get_all_groups} ->
		send(From, {all_groups, L}),
	    server_loop(L);
	%% Ex 3
	Msg ->
	    io:format("Server received Msg=~p~n", [Msg]),
	    server_loop(L)
    end.

wait_get_nicks_response() ->
    receive
	    {mm, _From, {nicks,Nicks}} -> 
		    {nicks_in_group, Nicks};
	    Other ->
		    io:format("chat_server unexpected message waiting nicks =~p~n", [Other]),
		    wait_get_nicks_response()
     end.


lookup(G, [{G, Address, Port, Channel}|_]) -> {ok, Address, Port, Channel};
lookup(G, [_|T])       -> lookup(G, T);
lookup(_,[])           -> error.

remove_group(G, [{G, _, _, _}|T]) -> io:format("~p removed~n",[G]), T;
remove_group(G, [H|T])       -> [H|remove_group(G, T)];
remove_group(_, [])            -> [].
